home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / comm / rzsz0916.zip / SZ.C < prev    next >
C/C++ Source or Header  |  1995-08-11  |  36KB  |  1,630 lines

  1. #define VERSION "3.40 02-21-95"
  2. #define PUBDIR "/usr/spool/uucppublic"
  3.  
  4. /*
  5.  **************************************************************************
  6.  *
  7.  * sz.c By Chuck Forsberg,  Omen Technology INC
  8.  *    Copyright 1995 Omen Technology Inc All Rights Reserved
  9.  * 
  10.  *********************************************************************
  11.  *********************************************************************
  12.  * 
  13.  *
  14.  *    This version implements numerous enhancements including ZMODEM
  15.  *    Run Length Encoding and variable length headers.  These
  16.  *    features were not funded by the original Telenet development
  17.  *    contract.
  18.  * 
  19.  * 
  20.  * This software may be freely used for educational (didactic
  21.  * only) purposes.  "Didactic" means it is used as a study item
  22.  * in a course teaching the workings of computer protocols.
  23.  * 
  24.  * This software may also be freely used to support file transfer
  25.  * operations to or from duly licensed Omen Technology products.
  26.  * This includes DSZ, GSZ, ZCOMM, Professional-YAM and PowerCom.
  27.  * Institutions desiring to use rz/sz this way should add the
  28.  * following to the sz compile line:    -DCOMPL
  29.  * Programs based on stolen or public domain ZMODEM materials are
  30.  * not included.  Use with other commercial or shareware programs
  31.  * (Crosstalk, Procomm, etc.) REQUIRES REGISTRATION.
  32.  * 
  33.  *
  34.  *  Any programs which incorporate part or all of this code must be
  35.  *  provided in source form with this notice intact except by
  36.  *  prior written permission from Omen Technology Incorporated.
  37.  *  This includes compiled executables of this program.
  38.  *
  39.  *   The .doc files and the file "mailer.rz" must also be included.
  40.  * 
  41.  * Use of this software for commercial or administrative purposes
  42.  * except when exclusively limited to interfacing Omen Technology
  43.  * products requires license payment of $20.00 US per user
  44.  * (less in quantity, see mailer.rz).  Use of this code by
  45.  * inclusion, decompilation, reverse engineering or any other means
  46.  * constitutes agreement to these conditions and acceptance of
  47.  * liability to license the materials and payment of reasonable
  48.  * legal costs necessary to enforce this license agreement.
  49.  *
  50.  *
  51.  *        Omen Technology Inc
  52.  *        Post Office Box 4681
  53.  *        Portland OR 97208
  54.  *
  55.  *    This code is made available in the hope it will be useful,
  56.  *    BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY
  57.  *    DAMAGES OF ANY KIND.
  58.  *
  59.  *  USG UNIX (3.0) ioctl conventions courtesy Jeff Martin
  60.  */
  61.  
  62. char *Copyrsz = "Copyright 1995 Omen Technology Inc All Rights Reserved";
  63.  
  64. char *substr();
  65.  
  66. #define LOGFILE "/tmp/szlog"
  67. #define LOGFILE2 "szlog"
  68. #include <stdio.h>
  69. #include <signal.h>
  70. #include <ctype.h>
  71. #include <errno.h>
  72. extern int errno;
  73. #define STATIC
  74.  
  75. #define PATHLEN 1000
  76. #define OK 0
  77. #define FALSE 0
  78. #ifdef TRUE
  79. #undef TRUE
  80. #endif
  81. #define TRUE 1
  82. #define ERROR (-1)
  83. /* Ward Christensen / CP/M parameters - Don't change these! */
  84. #define ENQ 005
  85. #define CAN ('X'&037)
  86. #define XOFF ('s'&037)
  87. #define XON ('q'&037)
  88. #define SOH 1
  89. #define STX 2
  90. #define EOT 4
  91. #define ACK 6
  92. #define NAK 025
  93. #define CPMEOF 032
  94. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  95. #define WANTG 0107    /* Send G not NAK to get nonstop batch xmsn */
  96. #define TIMEOUT (-2)
  97. #define RCDO (-3)
  98. #define GCOUNT (-4)
  99. #define RETRYMAX 10
  100.  
  101.  
  102. #define HOWMANY 2
  103. STATIC int Zmodem=0;        /* ZMODEM protocol requested by receiver */
  104. unsigned Baudrate = 9600;        /* Default, set by first mode() call */
  105. STATIC unsigned Txwindow;    /* Control the size of the transmitted window */
  106. STATIC unsigned Txwspac;    /* Spacing between zcrcq requests */
  107. STATIC unsigned Txwcnt;    /* Counter used to space ack requests */
  108. STATIC long Lrxpos;    /* Receiver's last reported offset */
  109. STATIC int errors;
  110. char endmsg[80] = {0};    /* Possible message to display on exit */
  111. char Zsendmask[33];    /* Additional control chars to mask */
  112.  
  113. #include "rbsb.c"    /* most of the system dependent stuff here */
  114.  
  115. #include "crctab.c"
  116.  
  117. STATIC int Filesleft;
  118. STATIC long Totalleft;
  119.  
  120. /*
  121.  * Attention string to be executed by receiver to interrupt streaming data
  122.  *  when an error is detected.  A pause (0336) may be needed before the
  123.  *  ^C (03) or after it.
  124.  */
  125. #ifdef READCHECK
  126. STATIC char Myattn[] = { 0 };
  127. #else
  128. #ifdef USG
  129. STATIC char Myattn[] = { 03, 0336, 0 };
  130. #endif
  131. #endif
  132.  
  133. FILE *in;
  134.  
  135. STATIC int Canseek = 1;    /* 1: Can seek 0: only rewind -1: neither (pipe) */
  136.  
  137. #ifndef TXBSIZE
  138. #define TXBSIZE 32768
  139. #endif
  140.  
  141. #define TXBMASK (TXBSIZE-1)
  142. STATIC char Txb[TXBSIZE];        /* Circular buffer for file reads */
  143. STATIC char *txbuf = Txb;        /* Pointer to current file segment */
  144. STATIC long vpos = 0;        /* Number of bytes read from file */
  145.  
  146. STATIC char Lastrx;
  147. STATIC char Crcflg;
  148. STATIC int Modem2=0;        /* XMODEM Protocol - don't send pathnames */
  149. STATIC int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  150. STATIC int Fullname=0;        /* transmit full pathname */
  151. STATIC int Unlinkafter=0;    /* Unlink file after it is sent */
  152. STATIC int Dottoslash=0;    /* Change foo.bar.baz to foo/bar/baz */
  153. STATIC int firstsec;
  154. STATIC int errcnt=0;        /* number of files unreadable */
  155. STATIC int Skipbitch=0;
  156. STATIC int blklen=128;        /* length of transmitted records */
  157. STATIC int Optiong;        /* Let it rip no wait for sector ACK's */
  158. STATIC int Eofseen;        /* EOF seen on input set by zfilbuf */
  159. STATIC int BEofseen;        /* EOF seen on input set by fooseek */
  160. STATIC int Totsecs;        /* total number of sectors this file */
  161. STATIC int Filcnt=0;        /* count of number of files opened */
  162. STATIC unsigned Rxbuflen=16384;    /* Receiver's max buffer length */
  163. STATIC long Tframlen = 0;    /* Override for tx frame length */
  164. STATIC int blkopt=0;        /* Override value for zmodem blklen */
  165. STATIC int Rxflags = 0;
  166. STATIC long bytcnt;
  167. STATIC int Wantfcs32 = TRUE;    /* want to send 32 bit FCS */
  168. STATIC char Lzconv;    /* Local ZMODEM file conversion request */
  169. STATIC char Lzmanag;    /* Local ZMODEM file management request */
  170. STATIC int Lskipnocor;
  171. STATIC char Lztrans;
  172. STATIC int Command;        /* Send a command, then exit. */
  173. STATIC char *Cmdstr;        /* Pointer to the command string */
  174. STATIC int Cmdack1;        /* Rx ACKs command, then do it */
  175. STATIC int Exitcode;
  176. STATIC int Test;        /* 1= Force receiver to send Attn, etc with qbf. */
  177.             /* 2= Character transparency test */
  178. STATIC char *qbf=
  179.  "The quick brown fox jumped over the lazy dog's back 1234567890\r\n";
  180. STATIC long Lastsync;    /* Last offset to which we got a ZRPOS */
  181. STATIC int Beenhereb4;        /* How many times we've been ZRPOS'd here */
  182. STATIC int Ksendstr;        /* 1= Send esc-?-3-4-l to remote kermit */
  183. STATIC char *ksendbuf = "\033[?34l";
  184.  
  185. STATIC jmp_buf intrjmp;    /* For the interrupt on RX CAN */
  186.  
  187.  
  188. /* called by signal interrupt or terminate to clean things up */
  189. void
  190. bibi(n)
  191. {
  192.     canit(); fflush(stdout); mode(0);
  193.     fprintf(stderr, "sz: caught signal %d; exiting\n", n);
  194.     if (n == SIGQUIT)
  195.         abort();
  196.     if (n == 99)
  197.         fprintf(stderr, "mode(2) in rbsb.c not implemented!!\n");
  198.     exit(3);
  199. }
  200.  
  201. /* Called when ZMODEM gets an interrupt (^X) */
  202. void
  203. onintr(c)
  204. {
  205.     signal(SIGINT, SIG_IGN);
  206.     longjmp(intrjmp, -1);
  207. }
  208.  
  209. STATIC int Zctlesc;    /* Encode control characters */
  210. STATIC int Nozmodem = 0;    /* If invoked as "sb" */
  211. STATIC char *Progname = "sz";
  212. STATIC int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  213.  
  214. /*
  215.  * Log an error
  216.  */
  217. /*VARARGS1*/
  218. void
  219. zperr(s,p,u)
  220. char *s, *p, *u;
  221. {
  222.     if (Verbose <= 0)
  223.         return;
  224.     fprintf(stderr, "Retry %d: ", errors);
  225.     fprintf(stderr, s, p, u);
  226.     fprintf(stderr, "\n");
  227. }
  228.  
  229. #include "zm.c"
  230. #include "zmr.c"
  231.  
  232. main(argc, argv)
  233. char *argv[];
  234. {
  235.     register char *cp;
  236.     register npats;
  237.     char **patts;
  238.  
  239.     if ((cp = getenv("ZNULLS")) && *cp)
  240.         Znulls = atoi(cp);
  241.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  242.         Restricted=TRUE;
  243.     inittty();
  244.     chkinvok(argv[0]);
  245.  
  246.     Rxtimeout = 600;
  247.     npats=0;
  248.     if (argc<2)
  249.         usage();
  250.     while (--argc) {
  251.         cp = *++argv;
  252.         if (*cp++ == '-' && *cp) {
  253.             while ( *cp) {
  254.                 if (isdigit(*cp)) {
  255.                     ++cp;  continue;
  256.                 }
  257.                 switch(*cp++) {
  258.                 case '\\':
  259.                      *cp = toupper(*cp);  continue;
  260.                 case '+':
  261.                     Lzmanag = ZMAPND; break;
  262.                 case 'a':
  263.                     if (Nozmodem || Modem2)
  264.                         usage();
  265.                     Lzconv = ZCNL;  break;
  266.                 case 'b':
  267.                     Lzconv = ZCBIN; break;
  268.                 case 'c':
  269.                     Lzmanag = ZMCHNG;  break;
  270.                 case 'd':
  271.                     ++Dottoslash;
  272.                     /* **** FALL THROUGH TO **** */
  273.                 case 'f':
  274.                     Fullname=TRUE; break;
  275.                         case 'g' :
  276.                     Ksendstr = TRUE; break;
  277.                 case 'e':
  278.                     Zctlesc = 1; break;
  279.                 case 'k':
  280.                     blklen=1024; break;
  281.                 case 'L':
  282.                     if (isdigit(*cp))
  283.                         blkopt = atoi(cp);
  284.                     else {
  285.                         if (--argc < 1)
  286.                             usage();
  287.                         blkopt = atoi(*++argv);
  288.                     }
  289.                     if (blkopt<24 || blkopt>1024)
  290.                         usage();
  291.                     break;
  292.                 case 'l':
  293.                     if (isdigit(*cp))
  294.                         Tframlen = atol(cp);
  295.                     else {
  296.                         if (--argc < 1)
  297.                             usage();
  298.                         Tframlen = atol(*++argv);
  299.                     }
  300.                     if (Tframlen<32 || Tframlen>65535L)
  301.                         usage();
  302.                     break;
  303.                 case 'N':
  304.                     Lzmanag = ZMNEWL;  break;
  305.                 case 'n':
  306.                     Lzmanag = ZMNEW;  break;
  307.                 case 'o':
  308.                     Wantfcs32 = FALSE; break;
  309.                 case 'p':
  310.                     Lzmanag = ZMPROT;  break;
  311.                 case 'r':
  312.                     if (Lzconv == ZCRESUM)
  313.                         Lzmanag = (Lzmanag & ZMMASK) | ZMCRC;
  314.                     Lzconv = ZCRESUM; break;
  315.                 case 'T':
  316.                     chartest(1); chartest(2);
  317.                     mode(0);  exit(0);
  318.                 case 'u':
  319.                     ++Unlinkafter; break;
  320.                 case 'v':
  321.                     ++Verbose; break;
  322.                 case 'w':
  323.                     if (isdigit(*cp))
  324.                         Txwindow = atoi(cp);
  325.                     else {
  326.                         if (--argc < 1)
  327.                             usage();
  328.                         Txwindow = atoi(*++argv);
  329.                     }
  330.                     if (Txwindow < 256)
  331.                         Txwindow = 256;
  332.                     Txwindow = (Txwindow/64) * 64;
  333.                     Txwspac = Txwindow/4;
  334.                     if (blkopt > Txwspac
  335.                      || (!blkopt && Txwspac < 1024))
  336.                         blkopt = Txwspac;
  337.                     break;
  338.                 case 'x':
  339.                     Skipbitch = 1;  break;
  340.                 case 'Y':
  341.                     Lskipnocor = TRUE;
  342.                     /* **** FALLL THROUGH TO **** */
  343.                 case 'y':
  344.                     Lzmanag = ZMCLOB; break;
  345.                 case 'Z':
  346.                 case 'z':
  347.                     Lztrans = ZTRLE;  break;
  348.                 default:
  349.                     usage();
  350.                 }
  351.             }
  352.         }
  353.         else if (Command) {
  354.             if (argc != 1) {
  355.                 usage();
  356.             }
  357.             Cmdstr = *argv;
  358.         }
  359.         else if ( !npats && argc>0) {
  360.             if (argv[0][0]) {
  361.                 npats=argc;
  362.                 patts=argv;
  363.             }
  364.         }
  365.     }
  366.     if (npats < 1 && !Command && !Test) 
  367.         usage();
  368.     if (Verbose) {
  369.         if (freopen(LOGFILE, "a", stderr)==NULL)
  370.             if (freopen(LOGFILE2, "a", stderr)==NULL) {
  371.                 printf("Can't open log file!");
  372.                 exit(2);
  373.             }
  374.         setbuf(stderr, NULL);
  375.     }
  376.     vfile("%s %s for %s tty=%s\n", Progname, VERSION, OS, Nametty);
  377.  
  378.     mode(3);
  379.  
  380.     if (signal(SIGINT, bibi) == SIG_IGN) {
  381.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  382.     } else {
  383.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  384.     }
  385. #ifdef SIGQUIT
  386.     signal(SIGQUIT, SIG_IGN);
  387. #endif
  388. #ifdef SIGTERM
  389.     signal(SIGTERM, bibi);
  390. #endif
  391.  
  392.     countem(npats, patts);
  393.  
  394.     if (!Modem2 && !Nozmodem) {
  395.         if (Ksendstr)
  396.             printf(ksendbuf);
  397.         printf("rz\r");  fflush(stdout);
  398.         stohdr(0x80L);    /* Show we can var header */
  399.         if (Command)
  400.             Txhdr[ZF0] = ZCOMMAND;
  401.         zshhdr(4, ZRQINIT, Txhdr);
  402.     }
  403.     fflush(stdout);
  404.  
  405.  
  406.     if (Command) {
  407.         if (getzrxinit()) {
  408.             Exitcode=1; canit();
  409.         }
  410.         else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
  411.             Exitcode=1; canit();
  412.         }
  413.     } else if (wcsend(npats, patts)==ERROR) {
  414.         Exitcode=1;
  415.         canit();
  416.     }
  417.     if (endmsg[0]) {
  418.         printf("\r\n%s: %s\r\n", Progname, endmsg);
  419.         if (Verbose)
  420.             fprintf(stderr, "%s\r\n", endmsg);
  421.     }
  422.     printf("%s %s finished.\r\n", Progname, VERSION);
  423.     fflush(stdout);
  424.     mode(0);
  425.     if(errcnt || Exitcode)
  426.         exit(1);
  427.  
  428. #ifndef REGISTERED
  429.     /* Removing or disabling this code without registering is theft */
  430.     if (!Usevhdrs)  {
  431.         printf("\n\n\nPlease read the License Agreement in sz.doc\n");
  432.         fflush(stdout);
  433.         sleep(10);
  434.     }
  435. #endif
  436.     exit(0);
  437.     /*NOTREACHED*/
  438. }
  439.  
  440. /* Say "bibi" to the receiver, try to do it cleanly */
  441. void
  442. saybibi()
  443. {
  444.     for (;;) {
  445.         stohdr(0L);        /* CAF Was zsbhdr - minor change */
  446.         zshhdr(4, ZFIN, Txhdr);    /*  to make debugging easier */
  447.         switch (zgethdr(Rxhdr)) {
  448.         case ZFIN:
  449.             sendline('O'); sendline('O'); flushmo();
  450.         case ZCAN:
  451.         case TIMEOUT:
  452.             return;
  453.         }
  454.     }
  455. }
  456.  
  457. wcsend(argc, argp)
  458. char *argp[];
  459. {
  460.     register n;
  461.  
  462.     Crcflg=FALSE;
  463.     firstsec=TRUE;
  464.     bytcnt = -1;
  465.     vfile("wcsend: argc=%d", argc);
  466.     if (Nozmodem) {
  467.         printf("Start your local YMODEM receive.     ");
  468.         fflush(stdout);
  469.     }
  470.     for (n=0; n<argc; ++n) {
  471.         Totsecs = 0;
  472.         if (wcs(argp[n])==ERROR)
  473.             return ERROR;
  474.     }
  475.     Totsecs = 0;
  476.     if (Filcnt==0) {    /* bitch if we couldn't open ANY files */
  477.         if (!Nozmodem && !Modem2) {
  478.             Command = TRUE;
  479.             Cmdstr = "echo \"sz: Can't open any requested files\"";
  480.             if (getnak()) {
  481.                 Exitcode=1; canit();
  482.             }
  483.             if (!Zmodem)
  484.                 canit();
  485.             else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
  486.                 Exitcode=1; canit();
  487.             }
  488.             Exitcode = 1; return OK;
  489.         }
  490.         canit();
  491.         sprintf(endmsg, "Can't open any requested files");
  492.         return ERROR;
  493.     }
  494.     if (Zmodem)
  495.         saybibi();
  496.     else if ( !Modem2)
  497.         wctxpn("");
  498.     return OK;
  499. }
  500.  
  501. wcs(oname)
  502. char *oname;
  503. {
  504.     register c;
  505.     register char *p;
  506.     struct stat f;
  507.     char name[PATHLEN];
  508.  
  509.     strcpy(name, oname);
  510.     vfile("wcs: name=%s", name);
  511.  
  512.     if (Restricted) {
  513.         /* restrict pathnames to current tree or uucppublic */
  514.         if ( substr(name, "../")
  515.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  516.             canit();  sprintf(endmsg,"Security Violation");
  517.             return ERROR;
  518.         }
  519.     }
  520.  
  521. #ifdef TXBSIZE
  522.     if ( !strcmp(name, "-")) {
  523.         if ((p = getenv("ONAME")) && *p)
  524.             strcpy(name, p);
  525.         else
  526.             sprintf(name, "s%d.sz", getpid());
  527.         in = stdin;
  528.     }
  529.     else
  530. #endif
  531.         in=fopen(name, "r");
  532.  
  533.     if (in==NULL) {
  534.         ++errcnt;
  535.         return OK;    /* pass over it, there may be others */
  536.     }
  537.     BEofseen = Eofseen = 0;  vpos = 0;
  538.  
  539.     /* Check for directory */
  540.     fstat(fileno(in), &f);
  541. #ifdef POSIX
  542.     if (S_ISDIR(f.st_mode))
  543. #else
  544.     c = f.st_mode & S_IFMT;
  545.     if (c == S_IFDIR || c == S_IFBLK)
  546. #endif
  547.     {
  548.         fclose(in);
  549.         return OK;
  550.     }
  551.  
  552.     ++Filcnt;
  553.     switch (wctxpn(name)) {
  554.     case ZSKIP:
  555.     case ZFERR:
  556.         return OK;
  557.     case OK:
  558.         break;
  559.     default:
  560.         return ERROR;
  561.     }
  562.     if (!Zmodem && wctx(f.st_size))
  563.         return ERROR;
  564.  
  565.     if (Unlinkafter)
  566.         unlink(oname);
  567.  
  568.     return 0;
  569. }
  570.  
  571. /*
  572.  * generate and transmit pathname block consisting of
  573.  *  pathname (null terminated),
  574.  *  file length, mode time and file mode in octal
  575.  *  as provided by the Unix fstat call.
  576.  *  N.B.: modifies the passed name, may extend it!
  577.  */
  578. wctxpn(name)
  579. char *name;
  580. {
  581.     register char *p, *q;
  582.     char name2[PATHLEN];
  583.     struct stat f;
  584.  
  585.     vfile("wctxpn: %s", name);
  586.     if (Modem2) {
  587.         if (*name && fstat(fileno(in), &f)!= -1) {
  588.             fprintf(stderr, "Sending %s, %ld XMODEM blocks. ",
  589.               name, (127+f.st_size)>>7);
  590.         }
  591.         printf("Start your local XMODEM receive.     ");
  592.         fflush(stdout);
  593.         return OK;
  594.     }
  595.     zperr("Awaiting pathname nak for %s", *name?name:"<END>");
  596.     if ( !Zmodem)
  597.         if (getnak())
  598.             return ERROR;
  599.  
  600.     q = (char *) 0;
  601.     if (Dottoslash) {        /* change . to . */
  602.         for (p=name; *p; ++p) {
  603.             if (*p == '/')
  604.                 q = p;
  605.             else if (*p == '.')
  606.                 *(q=p) = '/';
  607.         }
  608.         if (q && strlen(++q) > 8) {    /* If name>8 chars */
  609.             q += 8;            /*   make it .ext */
  610.             strcpy(name2, q);    /* save excess of name */
  611.             *q = '.';
  612.             strcpy(++q, name2);    /* add it back */
  613.         }
  614.     }
  615.  
  616.     for (p=name, q=txbuf ; *p; )
  617.         if ((*q++ = *p++) == '/' && !Fullname)
  618.             q = txbuf;
  619.     *q++ = 0;
  620.     p=q;
  621.     while (q < (txbuf + 1024))
  622.         *q++ = 0;
  623.     if (*name) {
  624.         if (fstat(fileno(in), &f)!= -1)
  625.             sprintf(p, "%lu %lo %o 3 %d %ld", f.st_size, f.st_mtime,
  626.               f.st_mode, Filesleft, Totalleft);
  627.         Totalleft -= f.st_size;
  628.     }
  629.     if (--Filesleft <= 0)
  630.         Filesleft = Totalleft = 0;
  631.     if (Totalleft < 0)
  632.         Totalleft = 0;
  633.  
  634.     /* force 1k blocks if name won't fit in 128 byte block */
  635.     if (txbuf[125])
  636.         blklen=1024;
  637.     else {        /* A little goodie for IMP/KMD */
  638.         txbuf[127] = (f.st_size + 127) >>7;
  639.         txbuf[126] = (f.st_size + 127) >>15;
  640.     }
  641.     vfile("wctxpn: %s", p);
  642.     if (Zmodem)
  643.         return zsendfile(txbuf, 1+strlen(p)+(p-txbuf));
  644.     if (wcputsec(txbuf, 0, 128)==ERROR)
  645.         return ERROR;
  646.     return OK;
  647. }
  648.  
  649. getnak()
  650. {
  651.     register firstch;
  652.  
  653.     Lastrx = 0;
  654.     for (;;) {
  655.         switch (firstch = readline(800)) {
  656.         case ZPAD:
  657.             if (getzrxinit())
  658.                 return ERROR;
  659.             return FALSE;
  660.         case TIMEOUT:
  661.             sprintf(endmsg, "Timeout waiting for ZRINIT");
  662.             return TRUE;
  663.         case WANTG:
  664. #ifdef MODE2OK
  665.             mode(2);    /* Set cbreak, XON/XOFF, etc. */
  666. #endif
  667.             Optiong = TRUE;
  668.             blklen=1024;
  669.         case WANTCRC:
  670.             Crcflg = TRUE;
  671.         case NAK:
  672.             return FALSE;
  673.         case CAN:
  674.             if ((firstch = readline(20)) == CAN && Lastrx == CAN) {
  675.                 sprintf(endmsg, "Got CAN waiting to send file");
  676.                 return TRUE;
  677.             }
  678.         default:
  679.             break;
  680.         }
  681.         Lastrx = firstch;
  682.     }
  683. }
  684.  
  685.  
  686. wctx(flen)
  687. long flen;
  688. {
  689.     register int thisblklen;
  690.     register int sectnum, attempts, firstch;
  691.     long charssent;
  692.  
  693.     charssent = 0;  firstsec=TRUE;  thisblklen = blklen;
  694.     vfile("wctx:file length=%ld", flen);
  695.  
  696.     while ((firstch=readline(Rxtimeout))!=NAK && firstch != WANTCRC
  697.       && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN)
  698.         ;
  699.     if (firstch==CAN) {
  700.         zperr("Receiver CANcelled");
  701.         return ERROR;
  702.     }
  703.     if (firstch==WANTCRC)
  704.         Crcflg=TRUE;
  705.     if (firstch==WANTG)
  706.         Crcflg=TRUE;
  707.     sectnum=0;
  708.     for (;;) {
  709.         if (flen <= (charssent + 896L))
  710.             thisblklen = 128;
  711.         if ( !filbuf(txbuf, thisblklen))
  712.             break;
  713.         if (wcputsec(txbuf, ++sectnum, thisblklen)==ERROR)
  714.             return ERROR;
  715.         charssent += thisblklen;
  716.     }
  717.     fclose(in);
  718.     attempts=0;
  719.     do {
  720.         purgeline();
  721.         sendline(EOT);
  722.         flushmo();
  723.         ++attempts;
  724.     }
  725.         while ((firstch=(readline(Rxtimeout)) != ACK) && attempts < RETRYMAX);
  726.     if (attempts == RETRYMAX) {
  727.         zperr("No ACK on EOT");
  728.         return ERROR;
  729.     }
  730.     else
  731.         return OK;
  732. }
  733.  
  734. wcputsec(buf, sectnum, cseclen)
  735. char *buf;
  736. int sectnum;
  737. int cseclen;    /* data length of this sector to send */
  738. {
  739.     register checksum, wcj;
  740.     register char *cp;
  741.     unsigned oldcrc;
  742.     int firstch;
  743.     int attempts;
  744.  
  745.     firstch=0;    /* part of logic to detect CAN CAN */
  746.  
  747.     if (Verbose>1)
  748.         fprintf(stderr, "Sector %3d %2dk\n", Totsecs, Totsecs/8 );
  749.     for (attempts=0; attempts <= RETRYMAX; attempts++) {
  750.         Lastrx= firstch;
  751.         sendline(cseclen==1024?STX:SOH);
  752.         sendline(sectnum);
  753.         sendline(-sectnum -1);
  754.         oldcrc=checksum=0;
  755.         for (wcj=cseclen,cp=buf; --wcj>=0; ) {
  756.             sendline(*cp);
  757.             oldcrc=updcrc((0377& *cp), oldcrc);
  758.             checksum += *cp++;
  759.         }
  760.         if (Crcflg) {
  761.             oldcrc=updcrc(0,updcrc(0,oldcrc));
  762.             sendline((int)oldcrc>>8);
  763.             sendline((int)oldcrc);
  764.         }
  765.         else
  766.             sendline(checksum);
  767.         flushmo();
  768.  
  769.         if (Optiong) {
  770.             firstsec = FALSE; return OK;
  771.         }
  772.         firstch = readline(Rxtimeout);
  773. gotnak:
  774.         switch (firstch) {
  775.         case CAN:
  776.             if(Lastrx == CAN) {
  777. cancan:
  778.                 zperr("Cancelled");  return ERROR;
  779.             }
  780.             break;
  781.         case TIMEOUT:
  782.             zperr("Timeout on sector ACK"); continue;
  783.         case WANTCRC:
  784.             if (firstsec)
  785.                 Crcflg = TRUE;
  786.         case NAK:
  787.             zperr("NAK on sector"); continue;
  788.         case ACK: 
  789.             firstsec=FALSE;
  790.             Totsecs += (cseclen>>7);
  791.             return OK;
  792.         case ERROR:
  793.             zperr("Got burst for sector ACK"); break;
  794.         default:
  795.             zperr("Got %02x for sector ACK", firstch); break;
  796.         }
  797.         for (;;) {
  798.             Lastrx = firstch;
  799.             if ((firstch = readline(Rxtimeout)) == TIMEOUT)
  800.                 break;
  801.             if (firstch == NAK || firstch == WANTCRC)
  802.                 goto gotnak;
  803.             if (firstch == CAN && Lastrx == CAN)
  804.                 goto cancan;
  805.         }
  806.     }
  807.     zperr("Retry Count Exceeded");
  808.     return ERROR;
  809. }
  810.  
  811. /* fill buf with count chars padding with ^Z for CPM */
  812. filbuf(buf, count)
  813. register char *buf;
  814. {
  815.     register m;
  816.  
  817.     m = read(fileno(in), buf, count);
  818.     if (m <= 0)
  819.         return 0;
  820.     while (m < count)
  821.         buf[m++] = 032;
  822.     return count;
  823. }
  824.  
  825. /* Fill buffer with blklen chars */
  826. zfilbuf()
  827. {
  828.     int n;
  829.  
  830. #ifdef TXBSIZE
  831.     vfile("zfilbuf: bytcnt =%lu vpos=%lu blklen=%d", bytcnt, vpos, blklen);
  832.     /* We assume request is within buffer, or just beyond */
  833.     txbuf = Txb + (bytcnt & TXBMASK);
  834.     if (vpos <= bytcnt) {
  835.         n = fread(txbuf, 1, blklen, in);
  836.  
  837.         vpos += n;
  838.         if (n < blklen)
  839.             Eofseen = 1;
  840.         vfile("zfilbuf: n=%d vpos=%lu Eofseen=%d", n, vpos, Eofseen);
  841.         return n;
  842.     }
  843.     if (vpos >= (bytcnt+blklen))
  844.         return blklen;
  845.     /* May be a short block if crash recovery etc. */
  846.     Eofseen = BEofseen;
  847.     return (vpos - bytcnt);
  848. #else
  849.     n = fread(txbuf, 1, blklen, in);
  850.     if (n < blklen) {
  851.         Eofseen = 1;
  852.         vfile("zfilbuf: n=%d vpos=%lu Eofseen=%d", n, vpos, Eofseen);
  853.     }
  854.     return n;
  855. #endif
  856. }
  857.  
  858. #ifdef TXBSIZE
  859. /* Replacement for brain damaged fseek function.  Returns 0==success */
  860. fooseek(fptr, pos, whence)
  861. FILE *fptr;
  862. long pos;
  863. {
  864.     long m, n;
  865.  
  866.     vfile("fooseek: pos =%lu vpos=%lu Canseek=%d", pos, vpos, Canseek);
  867.     /* Seek offset < current buffer */
  868.     if (pos < (vpos -TXBSIZE +1024)) {
  869.         BEofseen = 0;
  870.         if (Canseek > 0) {
  871.             vpos = pos & ~TXBMASK;
  872.             if (vpos >= pos)
  873.                 vpos -= TXBSIZE;
  874.             if (fseek(fptr, vpos, 0))
  875.                 return 1;
  876.         }
  877.         else if (Canseek == 0) {
  878.             if (fseek(fptr, vpos = 0L, 0))
  879.                 return 1;
  880.         } else
  881.             return 1;
  882.         while (vpos < pos) {
  883.             n = fread(Txb, 1, TXBSIZE, fptr);
  884.             vpos += n;
  885.             vfile("n=%d vpos=%ld", n, vpos);
  886.             if (n < TXBSIZE) {
  887.                 BEofseen = 1;
  888.                 break;
  889.             }
  890.         }
  891.         vfile("vpos=%ld", vpos);
  892.         return 0;
  893.     }
  894.     /* Seek offset > current buffer (Crash Recovery, etc.) */
  895.     if (pos > vpos) {
  896.         if (Canseek)
  897.             if (fseek(fptr, vpos = (pos & ~TXBMASK), 0))
  898.                 return 1;
  899.         while (vpos <= pos) {
  900.             txbuf = Txb + (vpos & TXBMASK);
  901.             m = TXBSIZE - (vpos & TXBMASK);
  902.             vfile("m=%ld vpos=%ld", m,vpos);
  903.                 n = fread(txbuf, 1, m, fptr);
  904.             vfile("n=%ld vpos=%ld", n,vpos);
  905.             vpos += n;
  906.             vfile("bo=%d m=%ld vpos=%ld", txbuf-Txb,m,vpos);
  907.             if (n < m) {
  908.                 BEofseen = 1;
  909.                 break;
  910.             }
  911.         }
  912.         return 0;
  913.     }
  914.     /* Seek offset is within current buffer */
  915.     vfile("within buffer: vpos=%ld", vpos);
  916.     return 0;
  917. }
  918. #define fseek fooseek
  919. #endif
  920.  
  921.  
  922. /*
  923.  * substr(string, token) searches for token in string s
  924.  * returns pointer to token within string if found, NULL otherwise
  925.  */
  926. char *
  927. substr(s, t)
  928. register char *s,*t;
  929. {
  930.     register char *ss,*tt;
  931.     /* search for first char of token */
  932.     for (ss=s; *s; s++)
  933.         if (*s == *t)
  934.             /* compare token with substring */
  935.             for (ss=s,tt=t; ;) {
  936.                 if (*tt == 0)
  937.                     return s;
  938.                 if (*ss++ != *tt++)
  939.                     break;
  940.             }
  941.     return NULL;
  942. }
  943.  
  944. char *usinfo[] = {
  945.     "Send Files and Commands with ZMODEM/YMODEM/XMODEM Protocol\n",
  946.     "Usage:    sz [-+abcdefgklLnNuvwxyYZ] [-] file ...",
  947.     "\t    zcommand [-egv] COMMAND",
  948.     "\t    zcommandi [-egv] COMMAND",
  949.     "\t    sb [-adfkuv] [-] file ...",
  950.     "\t    sx [-akuv] [-] file",
  951.     ""
  952. };
  953.  
  954. usage()
  955. {
  956.     char **pp;
  957.  
  958.     fprintf(stderr, "\n%s %s for %s by Chuck Forsberg, Omen Technology INC\n",
  959.      Progname, VERSION, OS);
  960.     fprintf(stderr, "\t\t\042The High Reliability Software\042\n");
  961.     for (pp=usinfo; **pp; ++pp)
  962.         fprintf(stderr, "%s\n", *pp);
  963.     fprintf(stderr,"\nCopyright (c) 1995 Omen Technology INC All Rights Reserved\n");
  964.     fprintf(stderr,
  965.      "See sz.doc for option descriptions and licensing information.\n\n");
  966.     fprintf(stderr,
  967.     "This program is designed to talk to terminal programs,\nnot to be called by one.\n");
  968.     fprintf(stderr,
  969.     "\nTechnical support hotline: 900-555-7836 (1-900-555-RTFM) $4.69/min.\n\n");
  970.     exit(3);
  971. }
  972.  
  973. /*
  974.  * Get the receiver's init parameters
  975.  */
  976. getzrxinit()
  977. {
  978.     register n;
  979.     struct stat f;
  980.  
  981.     for (n=10; --n>=0; ) {
  982.         
  983.         switch (zgethdr(Rxhdr)) {
  984.         case ZCHALLENGE:    /* Echo receiver's challenge numbr */
  985.             stohdr(Rxpos);
  986.             zshhdr(4, ZACK, Txhdr);
  987.             continue;
  988.         case ZCOMMAND:        /* They didn't see out ZRQINIT */
  989.             stohdr(0L);
  990.             zshhdr(4, ZRQINIT, Txhdr);
  991.             continue;
  992.         case ZRINIT:
  993.             if (Rxhlen==4 && (Rxhdr[ZF1] & ZRQNVH)) {
  994.                 stohdr(0x80L);    /* Show we can var header */
  995.                 zshhdr(4, ZRQINIT, Txhdr);
  996.                 continue;
  997.             }
  998.             Rxflags = 0377 & Rxhdr[ZF0];
  999. #if COMPL
  1000.             Usevhdrs = 1;
  1001. #else
  1002.             Usevhdrs = Rxhdr[ZF1] & CANVHDR;
  1003. #endif
  1004.             Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
  1005.             Zctlesc |= Rxflags & TESCCTL;
  1006.             if (Rxhdr[ZF1] & ZRRQQQ)    /* Escape ctrls */
  1007.                 initzsendmsk(Rxhdr+ZRPXQQ);
  1008.             Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
  1009.             if ( !(Rxflags & CANFDX))
  1010.                 Txwindow = 0;
  1011.             vfile("Rxbuflen=%d Tframlen=%ld", Rxbuflen, Tframlen);
  1012.             signal(SIGINT, SIG_IGN);
  1013. #ifdef MODE2OK
  1014.             mode(2);    /* Set cbreak, XON/XOFF, etc. */
  1015. #endif
  1016.  
  1017. #ifndef READCHECK
  1018. #ifndef USG
  1019.             /* Use 1024 byte frames if no sample/interrupt */
  1020.             if (Rxbuflen < 32 || Rxbuflen > 1024) {
  1021.                 Rxbuflen = 1024;
  1022.                 vfile("Rxbuflen=%d", Rxbuflen);
  1023.             }
  1024. #endif
  1025. #endif
  1026.  
  1027.             /* Override to force shorter frame length */
  1028.             if (Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32))
  1029.                 Rxbuflen = Tframlen;
  1030.             if ( !Rxbuflen && (Tframlen>=32))
  1031.                 Rxbuflen = Tframlen;
  1032.             vfile("Rxbuflen=%d", Rxbuflen);
  1033.  
  1034.  
  1035.             /*
  1036.              * If input is not a regular file, force ACK's to
  1037.              *  prevent running beyond the buffer limits
  1038.              */
  1039.             if ( !Command) {
  1040.                 fstat(fileno(in), &f);
  1041.                 if (
  1042. #ifdef POSIX
  1043.                     !S_ISREG(f.st_mode)
  1044. #else
  1045.                     (f.st_mode & S_IFMT) != S_IFREG
  1046. #endif
  1047.                     ) {
  1048.                     Canseek = -1;
  1049.                     f.st_size = 0;
  1050.                     f.st_mtime = 0;
  1051. #ifdef TXBSIZE
  1052.                     Txwindow = TXBSIZE - 1024;
  1053.                     Txwspac = TXBSIZE/4;
  1054. #else
  1055.                     sprintf(endmsg, "Can't seek on input");
  1056.                     return ERROR;
  1057. #endif
  1058.                 }
  1059.             }
  1060.  
  1061.             /* Set initial subpacket length */
  1062.             if (blklen < 1024) {    /* Command line override? */
  1063.                 if (Baudrate > 300)
  1064.                     blklen = 256;
  1065.                 if (Baudrate > 1200)
  1066.                     blklen = 512;
  1067.                 if (Baudrate > 2400)
  1068.                     blklen = 1024;
  1069.                 if (Baudrate < 300)
  1070.                     blklen = 1024;
  1071.             }
  1072.             if (Rxbuflen && blklen>Rxbuflen)
  1073.                 blklen = Rxbuflen;
  1074.             if (blkopt && blklen > blkopt)
  1075.                 blklen = blkopt;
  1076.             vfile("Rxbuflen=%d blklen=%d", Rxbuflen, blklen);
  1077.             vfile("Txwindow = %u Txwspac = %d", Txwindow, Txwspac);
  1078.  
  1079.  
  1080.             if (Lztrans == ZTRLE && (Rxflags & CANRLE))
  1081.                 Txfcs32 = 2;
  1082.             else
  1083.                 Lztrans = 0;
  1084.  
  1085.             return (sendzsinit());
  1086.         case ZCAN:
  1087.         case TIMEOUT:
  1088.             return ERROR;
  1089.         case ZRQINIT:
  1090.             if (Rxhdr[ZF0] == ZCOMMAND)
  1091.                 continue;
  1092.         default:
  1093.             zshhdr(4, ZNAK, Txhdr);
  1094.             continue;
  1095.         }
  1096.     }
  1097.     return ERROR;
  1098. }
  1099.  
  1100. /* Send send-init information */
  1101. sendzsinit()
  1102. {
  1103.     register c;
  1104.  
  1105.     if (Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL)))
  1106.         return OK;
  1107.     errors = 0;
  1108.     for (;;) {
  1109.         stohdr(0L);
  1110. #ifdef ALTCANOFF
  1111.         Txhdr[ALTCOFF] = ALTCANOFF;
  1112. #endif
  1113.         if (Zctlesc) {
  1114.             Txhdr[ZF0] |= TESCCTL; zshhdr(4, ZSINIT, Txhdr);
  1115.         }
  1116.         else
  1117.             zsbhdr(4, ZSINIT, Txhdr);
  1118.         zsdata(Myattn, ZATTNLEN, ZCRCW);
  1119.         c = zgethdr(Rxhdr);
  1120.         switch (c) {
  1121.         case ZCAN:
  1122.             return ERROR;
  1123.         case ZACK:
  1124.             return OK;
  1125.         default:
  1126.             if (++errors > 19)
  1127.                 return ERROR;
  1128.             continue;
  1129.         }
  1130.     }
  1131. }
  1132.  
  1133. /* Send file name and related info */
  1134. zsendfile(buf, blen)
  1135. char *buf;
  1136. {
  1137.     register c;
  1138.     register unsigned long crc;
  1139.     long lastcrcrq = -1;
  1140.  
  1141.     for (errors=0; ++errors<11;) {
  1142.         Txhdr[ZF0] = Lzconv;    /* file conversion request */
  1143.         Txhdr[ZF1] = Lzmanag;    /* file management request */
  1144.         if (Lskipnocor)
  1145.             Txhdr[ZF1] |= ZMSKNOLOC;
  1146.         Txhdr[ZF2] = Lztrans;    /* file transport request */
  1147.         Txhdr[ZF3] = 0;
  1148.         zsbhdr(4, ZFILE, Txhdr);
  1149.         zsdata(buf, blen, ZCRCW);
  1150. again:
  1151.         c = zgethdr(Rxhdr);
  1152.         switch (c) {
  1153.         case ZRINIT:
  1154.             while ((c = readline(50)) > 0)
  1155.                 if (c == ZPAD) {
  1156.                     goto again;
  1157.                 }
  1158.             continue;
  1159.         case ZCAN:
  1160.         case TIMEOUT:
  1161.         case ZABORT:
  1162.         case ZFIN:
  1163.             sprintf(endmsg, "Got %s on pathname", frametypes[c+FTOFFSET]);
  1164.             return ERROR;
  1165.         default:
  1166.             sprintf(endmsg, "Got %d frame type on pathname", c);
  1167.             continue;
  1168.         case ERROR:
  1169.         case ZNAK:
  1170.             continue;
  1171.         case ZCRC:
  1172.             if (Rxpos != lastcrcrq) {
  1173.                 lastcrcrq = Rxpos;
  1174.                 crc = 0xFFFFFFFFL;
  1175.                 if (Canseek >= 0) {
  1176.                     fseek(in, 0L, 0);
  1177.                     while (((c = getc(in)) != EOF) && --lastcrcrq)
  1178.                         crc = UPDC32(c, crc);
  1179.                     crc = ~crc;
  1180.                     clearerr(in);    /* Clear possible EOF */
  1181.                     lastcrcrq = Rxpos;
  1182.                 }
  1183.             }
  1184.             stohdr(crc);
  1185.             zsbhdr(4, ZCRC, Txhdr);
  1186.             goto again;
  1187.         case ZFERR:
  1188.         case ZSKIP:
  1189.             if (Skipbitch)
  1190.                 ++errcnt;
  1191.             sprintf(endmsg, "File skipped by receiver request");
  1192.             fclose(in); return c;
  1193.         case ZRPOS:
  1194.             /*
  1195.              * Suppress zcrcw request otherwise triggered by
  1196.              * lastyunc==bytcnt
  1197.              */
  1198.             if (fseek(in, Rxpos, 0))
  1199.                 return ERROR;
  1200.             Lastsync = (bytcnt = Txpos = Lrxpos = Rxpos) -1;
  1201.             return zsendfdata();
  1202.         }
  1203.     }
  1204.     fclose(in); return ERROR;
  1205. }
  1206.  
  1207. /* Send the data in the file */
  1208. zsendfdata()
  1209. {
  1210.     register c, e, n;
  1211.     register newcnt;
  1212.     register long tcount = 0;
  1213.     int junkcount;        /* Counts garbage chars received by TX */
  1214.     static int tleft = 6;    /* Counter for test mode */
  1215.  
  1216.     junkcount = 0;
  1217.     Beenhereb4 = FALSE;
  1218. somemore:
  1219.     if (setjmp(intrjmp)) {
  1220. waitack:
  1221.         junkcount = 0;
  1222.         c = getinsync(0);
  1223. gotack:
  1224.         switch (c) {
  1225.         default:
  1226.         case ZCAN:
  1227.             fclose(in);
  1228.             return ERROR;
  1229.         case ZRINIT:
  1230.             fclose(in);
  1231.             return ZSKIP;
  1232.         case ZSKIP:
  1233.             if (Skipbitch)
  1234.                 ++errcnt;
  1235.             fclose(in);
  1236.             return c;
  1237.         case ZACK:
  1238.         case ZRPOS:
  1239.             break;
  1240.         }
  1241. #ifdef READCHECK
  1242.         /*
  1243.          * If the reverse channel can be tested for data,
  1244.          *  this logic may be used to detect error packets
  1245.          *  sent by the receiver, in place of setjmp/longjmp
  1246.          *  rdchk(Tty) returns non 0 if a character is available
  1247.          */
  1248.         while (rdchk(Tty)) {
  1249. #ifdef EATSIT
  1250.             switch (checked)
  1251. #else
  1252.             switch (readline(1))
  1253. #endif
  1254.             {
  1255.             case CAN:
  1256.             case ZPAD:
  1257.                 c = getinsync(1);
  1258.                 goto gotack;
  1259.             case XOFF:        /* Wait a while for an XON */
  1260.                 readline(100);
  1261.             }
  1262.         }
  1263. #endif
  1264.     }
  1265.  
  1266.     signal(SIGINT, onintr);
  1267.     newcnt = Rxbuflen;
  1268.     Txwcnt = 0;
  1269.     stohdr(Txpos);
  1270.     zsbhdr(4, ZDATA, Txhdr);
  1271.  
  1272.     /*
  1273.      * Special testing mode.  This should force receiver to Attn,ZRPOS
  1274.      *  many times.  Each time the signal should be caught, causing the
  1275.      *  file to be started over from the beginning.
  1276.      */
  1277.     if (Test) {
  1278.         if ( --tleft)
  1279.             while (tcount < 20000) {
  1280.                 printf(qbf); fflush(stdout);
  1281.                 tcount += strlen(qbf);
  1282. #ifdef READCHECK
  1283.                 while (rdchk(Tty)) {
  1284. #ifdef EATSIT
  1285.                     switch (checked)
  1286. #else
  1287.                     switch (readline(1))
  1288. #endif
  1289.                     {
  1290.                     case CAN:
  1291.                     case ZPAD:
  1292.                         goto waitack;
  1293.                     case XOFF:    /* Wait for XON */
  1294.                         readline(100);
  1295.                     }
  1296.                 }
  1297. #endif
  1298.             }
  1299.         signal(SIGINT, SIG_IGN); canit();
  1300.         sleep(3); purgeline(); mode(0);
  1301.         printf("\nsz: Tcount = %ld\n", tcount);
  1302.         if (tleft) {
  1303.             printf("ERROR: Interrupts Not Caught\n");
  1304.             exit(1);
  1305.         }
  1306.         exit(0);
  1307.     }
  1308.  
  1309.     do {
  1310.         n = zfilbuf();
  1311.         if (Eofseen)
  1312.             e = ZCRCE;
  1313.         else if (junkcount > 3)
  1314.             e = ZCRCW;
  1315.         else if (bytcnt == Lastsync)
  1316.             e = ZCRCW;
  1317.         else if (Rxbuflen && (newcnt -= n) <= 0)
  1318.             e = ZCRCW;
  1319.         else if (Txwindow && (Txwcnt += n) >= Txwspac) {
  1320.             Txwcnt = 0;  e = ZCRCQ;
  1321.         } else
  1322.             e = ZCRCG;
  1323.         if (Verbose>1)
  1324.             fprintf(stderr, "%7ld ZMODEM%s\n",
  1325.               Txpos, Crc32t?" CRC-32":"");
  1326.         zsdata(txbuf, n, e);
  1327.         bytcnt = Txpos += n;
  1328.         if (e == ZCRCW)
  1329.             goto waitack;
  1330. #ifdef READCHECK
  1331.         /*
  1332.          * If the reverse channel can be tested for data,
  1333.          *  this logic may be used to detect error packets
  1334.          *  sent by the receiver, in place of setjmp/longjmp
  1335.          *  rdchk(Tty) returns non 0 if a character is available
  1336.          */
  1337.         fflush(stdout);
  1338.         while (rdchk(Tty)) {
  1339. #ifdef EATSIT
  1340.             switch (checked)
  1341. #else
  1342.             switch (readline(1))
  1343. #endif
  1344.             {
  1345.             case CAN:
  1346.             case ZPAD:
  1347.                 c = getinsync(1);
  1348.                 if (c == ZACK)
  1349.                     break;
  1350.                 /* zcrce - dinna wanna starta ping-pong game */
  1351.                 zsdata(txbuf, 0, ZCRCE);
  1352.                 goto gotack;
  1353.             case XOFF:        /* Wait a while for an XON */
  1354.                 readline(100);
  1355.             default:
  1356.                 ++junkcount;
  1357.             }
  1358.         }
  1359. #endif    /* READCHECK */
  1360.         if (Txwindow) {
  1361.             while ((tcount = (Txpos - Lrxpos)) >= Txwindow) {
  1362.                 vfile("%ld window >= %u", tcount, Txwindow);
  1363.                 if (e != ZCRCQ)
  1364.                     zsdata(txbuf, 0, e = ZCRCQ);
  1365.                 c = getinsync(1);
  1366.                 if (c != ZACK) {
  1367.                     zsdata(txbuf, 0, ZCRCE);
  1368.                     goto gotack;
  1369.                 }
  1370.             }
  1371.             vfile("window = %ld", tcount);
  1372.         }
  1373.     } while (!Eofseen);
  1374.     signal(SIGINT, SIG_IGN);
  1375.  
  1376.     for (;;) {
  1377.         stohdr(Txpos);
  1378.         zsbhdr(4, ZEOF, Txhdr);
  1379. egotack:
  1380.         switch (getinsync(0)) {
  1381.         case ZACK:
  1382.             goto egotack;
  1383.         case ZNAK:
  1384.             continue;
  1385.         case ZRPOS:
  1386.             goto somemore;
  1387.         case ZRINIT:
  1388.             fclose(in);
  1389.             return OK;
  1390.         case ZSKIP:
  1391.             if (Skipbitch)
  1392.                 ++errcnt;
  1393.             fclose(in);
  1394.             sprintf(endmsg, "File skipped by receiver request");
  1395.             return c;
  1396.         default:
  1397.             sprintf(endmsg, "Got %d trying to send end of file", c);
  1398.         case ERROR:
  1399.             fclose(in);
  1400.             return ERROR;
  1401.         }
  1402.     }
  1403. }
  1404.  
  1405. /*
  1406.  * Respond to receiver's complaint, get back in sync with receiver
  1407.  */
  1408. getinsync(flag)
  1409. {
  1410.     register c;
  1411.  
  1412.     for (;;) {
  1413.         if (Test) {
  1414.             printf("\r\n\n\n***** Signal Caught *****\r\n");
  1415.             Rxpos = 0; c = ZRPOS;
  1416.         } else
  1417.             c = zgethdr(Rxhdr);
  1418.         switch (c) {
  1419.         case ZCAN:
  1420.         case ZABORT:
  1421.         case ZFIN:
  1422.         case TIMEOUT:
  1423.             sprintf(endmsg, "Got %s sending data", frametypes[c+FTOFFSET]);
  1424.             return ERROR;
  1425.         case ZRPOS:
  1426.             if (Rxpos > bytcnt) {
  1427.                 sprintf(endmsg, "Nonstandard Protocol");
  1428.                 return ZRPOS;
  1429.             }
  1430.             /* ************************************* */
  1431.             /*  If sending to a buffered modem, you  */
  1432.             /*   might send a break at this point to */
  1433.             /*   dump the modem's buffer.         */
  1434.             clearerr(in);    /* In case file EOF seen */
  1435.             if (fseek(in, Rxpos, 0)) {
  1436.                 sprintf(endmsg, "Bad Seek");
  1437.                 return ERROR;
  1438.             }
  1439.             Eofseen = 0;
  1440.             bytcnt = Lrxpos = Txpos = Rxpos;
  1441.             if (Lastsync == Rxpos) {
  1442.                 if (++Beenhereb4 > 12) {
  1443.                     sprintf(endmsg, "Can't send block");
  1444.                     return ERROR;
  1445.                 }
  1446.                 if (Beenhereb4 > 4)
  1447.                     if (blklen > 32)
  1448.                         blklen /= 2;
  1449.             }
  1450.             Lastsync = Rxpos;
  1451.             return c;
  1452.         case ZACK:
  1453.             Lrxpos = Rxpos;
  1454.             if (flag || Txpos == Rxpos)
  1455.                 return ZACK;
  1456.             continue;
  1457.         case ZRINIT:
  1458.             return c;
  1459.         case ZSKIP:
  1460.             if (Skipbitch)
  1461.                 ++errcnt;
  1462.             sprintf(endmsg, "File skipped by receiver request");
  1463.             return c;
  1464.         case ERROR:
  1465.         default:
  1466.             zsbhdr(4, ZNAK, Txhdr);
  1467.             continue;
  1468.         }
  1469.     }
  1470. }
  1471.  
  1472.  
  1473. /* Send command and related info */
  1474. zsendcmd(buf, blen)
  1475. char *buf;
  1476. {
  1477.     register c;
  1478.     long cmdnum;
  1479.  
  1480.     cmdnum = getpid();
  1481.     errors = 0;
  1482.     for (;;) {
  1483.         stohdr(cmdnum);
  1484.         Txhdr[ZF0] = Cmdack1;
  1485.         zsbhdr(4, ZCOMMAND, Txhdr);
  1486.         zsdata(buf, blen, ZCRCW);
  1487. listen:
  1488.         Rxtimeout = 100;        /* Ten second wait for resp. */
  1489.         Usevhdrs = 0;        /* Allow rx to send fixed len headers */
  1490.         c = zgethdr(Rxhdr);
  1491.  
  1492.         switch (c) {
  1493.         case ZRINIT:
  1494.             goto listen;    /* CAF 8-21-87 */
  1495.         case ERROR:
  1496.         case GCOUNT:
  1497.         case TIMEOUT:
  1498.             if (++errors > 11)
  1499.                 return ERROR;
  1500.             continue;
  1501.         case ZCAN:
  1502.         case ZABORT:
  1503.         case ZFIN:
  1504.         case ZSKIP:
  1505.         case ZRPOS:
  1506.             return ERROR;
  1507.         default:
  1508.             if (++errors > 20)
  1509.                 return ERROR;
  1510.             continue;
  1511.         case ZCOMPL:
  1512.             Exitcode = Rxpos;
  1513.             saybibi();
  1514.             return OK;
  1515.         case ZRQINIT:
  1516.             vfile("******** RZ *******");
  1517.             system("rz");
  1518.             vfile("******** SZ *******");
  1519.             goto listen;
  1520.         }
  1521.     }
  1522. }
  1523.  
  1524. /*
  1525.  * If called as sb use YMODEM protocol
  1526.  */
  1527. chkinvok(s)
  1528. char *s;
  1529. {
  1530.     register char *p;
  1531.  
  1532.     p = s;
  1533.     while (*p == '-')
  1534.         s = ++p;
  1535.     while (*p)
  1536.         if (*p++ == '/')
  1537.             s = p;
  1538.     if (*s == 'v') {
  1539.         Verbose=1; ++s;
  1540.     }
  1541.     Progname = s;
  1542.     if (s[0]=='z' && s[1] == 'c') {
  1543.         Command = TRUE;
  1544.         if (s[8] == 'i')
  1545.             Cmdack1 = ZCACK1;
  1546.     }
  1547.     if (s[0]=='s' && s[1]=='b') {
  1548.         Nozmodem = TRUE; blklen=1024;
  1549.     }
  1550.     if (s[0]=='s' && s[1]=='x') {
  1551.         Modem2 = TRUE;
  1552.     }
  1553. }
  1554.  
  1555. countem(argc, argv)
  1556. register char **argv;
  1557. {
  1558.     struct stat f;
  1559.  
  1560.     for (Totalleft = 0, Filesleft = 0; --argc >=0; ++argv) {
  1561.         f.st_size = -1;
  1562.         if (Verbose>2) {
  1563.             fprintf(stderr, "\nCountem: %03d %s ", argc, *argv);
  1564.             fflush(stderr);
  1565.         }
  1566.         if (access(*argv, 04) >= 0 && stat(*argv, &f) >= 0) {
  1567.             ++Filesleft;  Totalleft += f.st_size;
  1568.         }
  1569.         if (Verbose>2)
  1570.             fprintf(stderr, " %ld", f.st_size);
  1571.     }
  1572.     if (Verbose>2)
  1573.         fprintf(stderr, "\ncountem: Total %d %ld\n",
  1574.           Filesleft, Totalleft);
  1575. }
  1576.  
  1577. chartest(m)
  1578. {
  1579.     register n;
  1580.  
  1581.     mode(m);
  1582.     printf("\r\n\nCharacter Transparency Test Mode %d\r\n", m);
  1583.     printf("If Pro-YAM/ZCOMM is not displaying ^M hit ALT-V NOW.\r\n");
  1584.     printf("Hit Enter.\021");  fflush(stdout);
  1585.     readline(500);
  1586.  
  1587.     for (n = 0; n < 256; ++n) {
  1588.         if (!(n%8))
  1589.             printf("\r\n");
  1590.         printf("%02x ", n);  fflush(stdout);
  1591.         sendline(n);    flushmo();
  1592.         printf("  ");  fflush(stdout);
  1593.         if (n == 127) {
  1594.             printf("Hit Enter.\021");  fflush(stdout);
  1595.             readline(500);
  1596.             printf("\r\n");  fflush(stdout);
  1597.         }
  1598.     }
  1599.     printf("\021\r\nEnter Characters, echo is in hex.\r\n");
  1600.     printf("Hit SPACE or pause 40 seconds for exit.\r\n");
  1601.  
  1602.     while (n != TIMEOUT && n != ' ') {
  1603.         n = readline(400);
  1604.         printf("%02x\r\n", n);
  1605.         fflush(stdout);
  1606.     }
  1607.     printf("\r\nMode %d character transparency test ends.\r\n", m);
  1608.     fflush(stdout);
  1609. }
  1610.  
  1611. /*
  1612.  * Set additional control chars to mask in Zsendmask
  1613.  * according to bit array stored in char array at p
  1614.  */
  1615. initzsendmsk(p)
  1616. register char *p;
  1617. {
  1618.     register c;
  1619.  
  1620.     for (c = 0; c < 33; ++c) {
  1621.         if (p[c>>3] & (1 << (c & 7))) {
  1622.             Zsendmask[c] = 1;
  1623.             vfile("Escaping %02o", c);
  1624.         }
  1625.     }
  1626. }
  1627.  
  1628.  
  1629. /* End of sz.c */
  1630.